iT邦幫忙

2026 iThome 鐵人賽

0
Vibe Coding

從一句話到一個網站:用 Vibe Coding 開發 WordPress Block Theme 的 30 天系列 第 32

WooCommerce 區塊初探:商品列表、購物車與結帳區塊

  • 分享至 

  • xImage
  •  

我在自己的站上(WooCommerce 10.9.1)數了一下註冊的區塊,一共有 165 個:

$blocks = array_filter(
	array_keys( WP_Block_Type_Registry::get_instance()->get_all_registered() ),
	fn( $name ) => str_starts_with( $name, 'woocommerce/' )
);
echo count( $blocks );   // 165

這個數字第一次看到會嚇一跳,但它其實說明了 WooCommerce 的設計思路:不是做幾個大區塊把整頁包起來,而是把每一個可見的元件都拆成獨立區塊。

165 個區塊怎麼分類

我把它們按前綴分了一下:

分類 數量 代表區塊
商品與目錄 56 product-collectionproduct-templateproduct-galleryproduct-reviews
結帳 24 checkoutcheckout-fields-blockcheckout-billing-address-block
篩選 18 product-filtersattribute-filterprice-filter
購物車 18 cartcart-line-items-blockcart-order-summary-block
訂單確認 14 order-confirmation-summaryorder-confirmation-totals
迷你購物車 11 mini-cartmini-cart-contents
其他 24 store-noticescustomer-accountbreadcrumbs

看這個分佈就懂了:結帳有 24 個區塊,不是因為結帳頁有 24 個功能,而是因為結帳頁的每一塊像是聯絡資訊、帳單地址、運送方式、付款方式、下單按鈕等等都是可以單獨移動、單獨隱藏的區塊。

這種把頁面拆成有邊界的 UI 元件然後在範本裡組裝,就是區塊的核心思路,差別只在 WooCommerce 幫你把電商需要的元件都做好了。

這邊以傳統的做法來做對比,就能知道 WooCommerce 區塊對應到哪些功能:

舊做法 新做法 備註
[woocommerce_cart] woocommerce/cart 內含 18 個子區塊
[woocommerce_checkout] woocommerce/checkout 內含 24 個子區塊
[products limit="8"] woocommerce/product-collection 取代舊的 Products by Category 等一系列區塊
[product_categories] woocommerce/product-categories
[woocommerce_my_account] woocommerce/customer-account 目前仍以連結為主
woocommerce_output_all_notices() woocommerce/store-notices 提示訊息的位置變成可控
woocommerce_breadcrumb() woocommerce/breadcrumbs
覆蓋 archive-product.php archive-product.html 區塊範本
覆蓋 single-product.php single-product.html 區塊範本

WooCommerce 自己提供的區塊範本放在外掛的 templates/templates/ 底下:

archive-product.html
page-cart.html
page-checkout.html
order-confirmation.html
blockified/           # 更徹底區塊化的版本

如果要客製化這些範本跟之前的做法一樣,只要在你的主題 templates/ 放一個同名的 HTML 檔就會蓋過去。

商品列表區塊

商品列表這一塊 WooCommerce 換過好幾代,現在的做法是 product-collection。它是之前文章有提到過的 Query Loop 的電商版,你設定查詢條件(分類、標籤、庫存狀態、排序),它負責查詢與迴圈,裡面放 product-template 決定每一張卡片長什麼樣。

理解它的關鍵是分清楚兩層:

  • product-collection = 查詢條件與版面(幾欄、幾筆、排序)
  • product-template = 單一商品卡片的內容(圖片、標題、價格、加入購物車)

上圖是修改商品列表的呈現邏輯,可以直接從 WooCommerce 內建的 Collection 進行選擇,然後右邊可以設定每欄的寬度、呈現的版面以及寬度。

點擊 Collection 區塊第二次後,就可以選到裡面的單一商品卡片的設定,每一個商品的圖片、商品名稱、樣式、價格,以及「加入購物車」按鈕,都有對應的功能可以進行設定。像是改變字型顏色、邊距、字體大小等,可以說是非常的靈活:

購物車區塊

woocommerce/cart 本身不畫任何東西,它是一個容器,真正的內容分成兩個狀態:

woocommerce/cart
├── woocommerce/filled-cart-block                    # 購物車有商品時
│   ├── woocommerce/cart-items-block
│   │   ├── woocommerce/cart-line-items-block        # 商品明細
│   │   └── woocommerce/cart-cross-sells-block       # 交叉銷售(可刪)
│   └── woocommerce/cart-totals-block
│       ├── woocommerce/cart-order-summary-block
│       │   ├── ...-heading-block                    # 「訂單摘要」標題(可刪)
│       │   ├── ...-coupon-form-block                # 折價券欄位(可刪)
│       │   ├── ...-subtotal-block                   # 小計
│       │   ├── ...-fee-block                        # 額外費用
│       │   ├── ...-discount-block                   # 折扣
│       │   ├── ...-shipping-block                   # 運費
│       │   └── ...-taxes-block                      # 稅金
│       ├── woocommerce/cart-express-payment-block           # Apple Pay 這類快速付款
│       ├── woocommerce/proceed-to-checkout-block            # 前往結帳按鈕
│       └── woocommerce/cart-accepted-payment-methods-block  # 付款方式圖示(可刪)
└── woocommerce/empty-cart-block                     # 購物車是空的時候

用傳統佈景主題的角度來看,這張圖其實就是舊範本檔的翻譯:

傳統範本檔 對應區塊
cart/cart.php filled-cart-block
cart/cart-empty.php empty-cart-block
cart/cart-totals.php cart-totals-block
cart/cross-sells.php cart-cross-sells-block
cart/proceed-to-checkout-button.php proceed-to-checkout-block

差別在於,以前空車跟有商品是兩個各自獨立的 PHP 檔案,要改空車畫面就得去覆蓋 cart-empty.php;現在兩種狀態都在同一個區塊裡,選到 woocommerce/cart 之後工具列會出現「Filled Cart / Empty Cart」的切換鈕,按一下就切到另一個狀態繼續編輯,存檔時兩份內容都寫進同一篇頁面裡。

這也解釋了為什麼「購物車」那一列會有 18 個區塊 — 光是右邊那塊金額摘要,小計、費用、折扣、運費、稅金就各自是一個獨立區塊。這樣拆的好處是,你想把稅金那一行的字改成灰色小字,就真的只改那一行,不用去動整個摘要區。

結帳頁區塊

結帳頁是同一套思路,容器加上左右兩欄:

woocommerce/checkout
├── woocommerce/checkout-fields-block            # 左欄:所有輸入欄位
│   ├── ...-express-payment-block                # 快速付款
│   ├── ...-contact-information-block            # 聯絡資訊(Email)
│   ├── ...-shipping-method-block                # 宅配或自取
│   ├── ...-pickup-options-block                 # 自取地點
│   ├── ...-shipping-address-block               # 運送地址
│   ├── ...-billing-address-block                # 帳單地址
│   ├── ...-shipping-methods-block               # 運送方式與運費
│   ├── ...-payment-block                        # 付款方式
│   ├── ...-additional-information-block         # 其他欄位
│   ├── ...-order-note-block                     # 訂單備註(可刪)
│   ├── ...-terms-block                          # 條款同意(可刪)
│   └── ...-actions-block                        # 下單按鈕
└── woocommerce/checkout-totals-block            # 右欄:訂單摘要(可刪)
    └── ...-order-summary-block
        ├── ...-cart-items-block                 # 訂單內的商品
        ├── ...-coupon-form-block                # 折價券欄位(可刪)
        └── ...-subtotal / fee / discount / shipping / taxes-block

一樣對照回傳統範本檔:

傳統範本檔 對應區塊
checkout/form-checkout.php checkout(容器)
checkout/form-billing.php checkout-billing-address-block
checkout/form-shipping.php checkout-shipping-address-block
checkout/payment.php checkout-payment-block
checkout/terms.php checkout-terms-block
checkout/review-order.php checkout-order-summary-block
checkout/form-coupon.php checkout-order-summary-coupon-form-block

這裡要先打破一個很容易產生的誤會。既然結帳頁變成區塊了,那欄位順序是不是就能在編輯器裡拖來拖去?答案是不行,因為它們是前端依照後端給的欄位定義畫出來的,排序依據寫在 src/Blocks/Domain/Services/CheckoutFields.php

'email'      => [ ..., 'index' => 0 ],
'country'    => [ ..., 'index' => 1 ],
'first_name' => [ ..., 'index' => 10 ],
'last_name'  => [ ..., 'index' => 20 ],

舊版靠 woocommerce_checkout_fields filter 裡的 priority 排序,新版靠 Checkout Fields API 的 index 排序,這也是為什麼點了某個子區塊,工具列沒有拖曳把手,選項選單裡也沒有「移除」,這是 WooCommerce 刻意鎖的。

每個子區塊的 block.json 都有一個 lock 屬性,預設值長這樣:

"lock": {
	"type": "object",
	"default": { "remove": true, "move": true }
}

remove: true 是不能刪、move: true 是不能搬,兩個是分開的。在 WooCommerce 10.9.1 裡,購物車與結帳底下能刪掉的只有這幾個:

  • cart-cross-sells-block:交叉銷售
  • cart-order-summary-heading-block:訂單摘要標題
  • cart-order-summary-coupon-form-blockcheckout-order-summary-coupon-form-block:折價券欄位
  • cart-accepted-payment-methods-block:付款方式圖示
  • checkout-order-note-block:訂單備註
  • checkout-terms-block:條款同意
  • checkout-totals-block:整個右欄的訂單摘要

簡單說跟「結帳流程能不能跑完」有關的都鎖住,純粹是行銷用或選配的才開放, 少了折價券欄位訂單照樣成立,少了付款方式區塊就沒辦法結帳了。

這是從傳統佈景主題轉過來最需要調整的心態。以前想拿掉付款區塊,一行 remove_action( 'woocommerce_checkout_order_review', 'woocommerce_checkout_payment', 20 ); 就解決了,好處是自由,壞處是很容易把結帳頁改壞而不自知,而且改壞的當下沒有任何警告。

現在 WooCommerce 用 lock 把必要環節保護起來,你能調的是樣式、文字與少數選配元件,這對交付給客戶自己維護的站來說是好事,客戶在編輯器裡怎麼玩都不會把結帳流程玩壞。

那如果真的需要在結帳頁加一個「發票抬頭」或「統一編號」欄位呢?那就不是刪區塊或加區塊的問題,而是要走 WooCommerce 開給你的擴充機制,之後的文章會提到

那舊的 WooCommerce 短代碼什麼時候還有用

不要以為新的一定比較好,有三種情況我還是會用舊做法:

一、要塞進非區塊編輯器的頁面內容

例如某個外掛產生的頁面、或者客戶還在用的 Elementor 版面,那裡沒有區塊可用,短代碼仍然是最簡單的解法。

二、需要大量 PHP 客製的商品列表

如果你要的查詢邏輯複雜到 WooCommerce 區塊的設定介面表達不出來(例如「同時符合三個自訂欄位條件、依庫存與銷量加權排序」),自己寫一個短代碼或動態區塊跑 WP_Query 反而乾淨。

三、舊站維護

客戶的站已經是短代碼結帳頁,運作正常也沒有客製需求那就別動它,WooCommerce 沒有要移除 短代碼,硬改只是給自己找麻煩。

判斷原則很單純:你要的東西如果是「版面與元件的組合」,用區塊;如果是「特殊的查詢或商業邏輯」,寫程式。

交給 AI 之前要先確認的一件事

要 AI 幫你組電商頁面時,最常見的錯誤不是它不會寫,而是它給你舊版的區塊名稱。WooCommerce 這幾年淘汰了一整批區塊(products-by-categoryhandpicked-products 這類都被 Product Collection 取代了),但網路上的舊文章還在,AI 就照著給。

驗證方法很直接,把區塊清單抓出來讓它對:

wp eval 'foreach ( array_keys( WP_Block_Type_Registry::get_instance()->get_all_registered() ) as $n ) { if ( str_starts_with( $n, "woocommerce/" ) ) { echo $n, "\n"; } }'

這一行會列出你這個站當下真正註冊的區塊。把它貼給 AI 當作可用清單,比讓它憑記憶猜可靠得多,這個做法在整個第四部都適用。WooCommerce 的 API 變動速度比 WordPress 核心快,當下的環境永遠比訓練資料準確。

區塊盤點完了,商品列表、購物車與結帳的組成也拆開看過了,但知道一個東西由哪些零件組成,跟知道這些零件怎麼運作是兩回事,下一篇我們來看資料在前後端之間怎麼流動,以及為什麼你熟悉的那些 PHP 勾點在這裡會失效。

文章目錄:https://oberonlai.blog/category/2026-ithome/


上一篇
電商也進入 Block 時代:WooCommerce 與區塊編輯器
系列文
從一句話到一個網站:用 Vibe Coding 開發 WordPress Block Theme 的 30 天32
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言